package cn.xhz.gdal.action;

import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
import cn.xhz.gdal.config.CommonConfig;
import cn.xhz.gdal.enums.FileModeEnum;
import cn.xhz.gdal.enums.GDALTypeEnum;
import cn.xhz.gdal.enums.ReadLayerModeEnum;
import cn.xhz.gdal.exception.GDALException;
import cn.xhz.gdal.model.GDAL;
import cn.xhz.gdal.util.Assert;
import cn.xhz.gdal.util.GDALUtils;
import cn.xhz.gdal.util.StringUtil;
import javafx.util.Builder;
import org.gdal.ogr.DataSource;
import org.gdal.ogr.Driver;
import org.gdal.ogr.Feature;
import org.gdal.ogr.Layer;

import java.io.File;
import java.util.List;
import java.util.Map;
import java.util.Objects;


/**
 * 不会关闭但其概念输入流 <br/>
 * 可以先初始化自己想要的驱动，读之前会检查，若是没有注册会进行注册<br/>
 * 请调用者在读的时候，用完该对象之后自行关闭
 * 读文件操作，也需要像Java文件流那样关闭对象
 * {@link cn.xhz.gdal.config.ConfigUtil#stopContext(GDAL)}
 * 最主要方法{@link #read()}
 * @author life-oss
 * @since 2022/12/13
 */
public class GDALRead extends CommonConfig{
    private final Log log = LogFactory.get();
    /**
     * 以下就是返回数据
     */
    public GDAL read(){
        checkRequired();
        initContext();
        Driver driver = getDriver();
        DataSource dataSource;
        boolean flag=getFileModeEnum().equals(FileModeEnum.READR)||getIgnoreGdalType().contains(getGdalTypeEnum());
        if (flag) {
            //只读对象
            dataSource=driver.Open(getPath());
        }else {
            dataSource=driver.Open(getPath(),1);
        }
        Layer layer = getLayer(dataSource);
        Map<Feature, Map<String, String>> data = getData(layer);
        //请传当前对象
        return GDAL.builder()
                .dataSource(dataSource)
                .layer(layer)
                .data(data)
                .build();
    }
    /**
     * 文件打开方式
     * 默认读+写
     * @see FileModeEnum
     */
    private FileModeEnum fileModeEnum=FileModeEnum.READER_AND_WRITE;
    /**
     * 是否选择获取图层
     * 默认获取
     */
    private Boolean getLayer=true;
    private ReadLayerModeEnum readLayerModeEnum=ReadLayerModeEnum.INDEX;
    /**
     * 获取数据
     */
    private Boolean gainData=true;

    /**
     * 该方法用于打开图层
     * @param dataSource
     * @return
     */
    public Layer getLayer(DataSource dataSource){
        if (!getGetLayer()||dataSource==null){
            return null;
        }
        Layer layer=null;
        ReadLayerModeEnum layerModeEnum = getReadLayerModeEnum();
        switch (layerModeEnum){
            case INDEX:
                int layerIndex = Integer.parseInt((String) layerModeEnum.getReadMode());
                if (dataSource.GetLayerCount()< layerIndex){
                    throw new GDALException("图层下标越界");
                }
                layer=dataSource.GetLayer(layerIndex);
                break;
            case NAME:
                String layerName=String.valueOf(layerModeEnum.getReadMode());
                if (!GDALUtils.isHaveLayer(dataSource,layerName)){
                    throw new GDALException("当前文件没有该图层");
                }
                layer=dataSource.GetLayer(layerName);
                break;
            default:
                break;
        }
        log.error("打开图层报错，当前调用参数为:{}",getReadLayerModeEnum());
        Assert.isNotNull(layer,"请检查当前数据源是否有图层，或者调用参数有问题");
        return layer;
    }

    /**
     * 获取数据
     * @param layer
     * @return
     */
    public Map<Feature, Map<String,String>> getData(Layer layer){
        if (!getGainData()||layer==null){
            return null;
        }
        return GDALUtils.getData(layer);
    }



    //====================默认生成get和set方法===============================
    //====================特殊说明会用注释标明================================


    public ReadLayerModeEnum getReadLayerModeEnum() {
        return readLayerModeEnum;
    }

    public void setReadLayerModeEnum(ReadLayerModeEnum readLayerModeEnum) {
        this.readLayerModeEnum = readLayerModeEnum;
    }

    public FileModeEnum getFileModeEnum() {
        return fileModeEnum;
    }

    public void setFileModeEnum(FileModeEnum fileModeEnum) {
        this.fileModeEnum = fileModeEnum;
    }

    public boolean isGetLayer() {
        return getLayer;
    }

    public void setGetLayer(boolean getLayer) {
        this.getLayer = getLayer;
    }


    public boolean isGainData() {
        return gainData;
    }

    public void setGainData(boolean gainData) {
        this.gainData = gainData;
    }

    public Boolean getGetLayer() {
        return getLayer;
    }

    public void setGetLayer(Boolean getLayer) {
        this.getLayer = getLayer;
    }

    public Boolean getGainData() {
        return gainData;
    }

    public void setGainData(Boolean gainData) {
        this.gainData = gainData;
    }

    //==============================建造者模式构建=============================

    public static GDALReadBuilder builder(){
        return new GDALReadBuilder();
    }
    public static class GDALReadBuilder implements Builder<GDALRead> {
        private GDALRead gdalRead=new GDALRead();

        public GDALReadBuilder path(File file){
            gdalRead.setPath(file);
            return this;
        }
        public GDALReadBuilder path(String path){
            gdalRead.setPath(path);
            return this;
        }
        public GDALReadBuilder gdalTypeEnum(GDALTypeEnum gdalTypeEnum){
            gdalRead.setGdalTypeEnum(gdalTypeEnum);
            return this;
        }
        public GDALReadBuilder initContext(boolean initContext){
            gdalRead.setInitContext(initContext);
            return this;
        }
        public GDALReadBuilder fileModeEnum(FileModeEnum fileModeEnum){
            gdalRead.setFileModeEnum(fileModeEnum);
            return this;
        }
        public GDALReadBuilder getLayer(boolean getLayer){
            gdalRead.setGetLayer(getLayer);
            return this;
        }
//        public GDALReadBuilder layerIndexParameter(boolean layerIndexParameter){
//            gdalRead.setLayerIndexParameter(layerIndexParameter);
//            return this;
//        }
//        public GDALReadBuilder layerIndex(int layerIndex){
//            gdalRead.setLayerIndex(layerIndex);
//            return this;
//        }
//        public GDALReadBuilder layerName(String layerName){
//            gdalRead.setLayerName(layerName);
//            return this;
//        }
        public GDALReadBuilder gainData(boolean gainData) {
            gdalRead.setGainData(gainData);
            return this;
        }
        @Override
        public GDALRead build(){
            return this.gdalRead;
        }

    }


}
